Route 53で管理しているドメインでDNSSECを有効化してみた
こんにちは、なおにしです。
Route 53はDNSSEC(Domain Name System Security Extensions)に対応しています。
DNSSECを使用することで、フルリゾルバ(DNSキャッシュサーバ)と各ゾーンの権威サーバ間における名前解決のデータのやり取りでデータの偽装を検知することができるようになるため、DNSキャッシュポイズニングなどの攻撃に対して備えることができます。
つまりRoute 53でDNSSECに対応するということは、以下の図の④の通信においてDNSSECが有効な名前解決が可能ということです。
今回はDNSSECが無効状態だった既存ドメイン(Route 53でドメインを取得・管理)に対して、DNSSECを有効化してみました。
DNSSEC有効化前
DNSゾーンの状態を可視化するオンラインツール「DNSViz」を使って可視化してみます。今回は対象ドメインのサブドメインとして登録しているWebサイトを指定して実行しました。
上記の可視化結果から分かることは、ルートゾーンとTLD(今回はcomゾーン)の間ではDNSSECによる信頼関係が結ばれていますが、comゾーンと今回DNSSECを有効化する対象のゾーン間では信頼関係が結ばれていないということです。
信頼の連鎖
DNSSECでは電子署名による「信頼の連鎖」という仕組みを用いて、子ゾーンの信頼性を親ゾーンに担保してもらいます。 この際に使用されるDNSのレコードおよびのその中身の概要については以下のとおりです。
- DNSKEYレコード:各レコードセットの署名に使用した秘密鍵に対応する公開鍵
- RRSIGレコード:各レコードセットに付加される電子署名
- DSレコード:公開鍵(DNSKEYレコード)に対応するハッシュ値
- NSEC3レコード:DNSSECの不在証明に使われるハッシュ値
親ゾーンと子ゾーンが信頼関係を結ぶには、子ゾーンのDSレコードを親ゾーンに登録・公開する必要があります。
リゾルバーによる名前解決では、ルートゾーンへの問い合わせから始まり、それぞれのゾーンの権威サーバから次に問い合わせをすべき権威サーバの情報を順に受け取りながら解決対象のレコードを知っている権威サーバに到達します。DNSSECが有効であればこのやり取りの際にDSレコードとRRSIGレコードも渡され、DNSKEYレコードとの照合も行われます。
したがって、「親ゾーンから受け取ったDSレコードと子ゾーンのDNSKEYレコードが照合できれば、子ゾーンのレコードセットは信頼できる(※)」という繰り返しによって、親ゾーンから子ゾーンに向かって順番に信頼がつながっていき、最終的に信頼されたレコードが返されることになります。
(※)正確には、DNSKEYレコードにはKSK(キー署名キー)公開鍵とZSK(ゾーン署名キー)公開鍵があり、それぞれの署名(RRSIG)を検証することによって目的のレコードを信頼しています。DNSKEYレコードはKSK秘密鍵によって署名され、DNSKEY以外のレコード(目的のAレコードなど。DSレコードも含む)はZSK秘密鍵によって署名されます。DSレコードは正確にはKSK公開鍵に対応するハッシュ値です。
RRSIGレコードについては上記の可視化結果には表示されていませんが、digコマンドを使って対象のドメインに対する名前解決をトレースすると、実際は以下のようにRRSIGレコードも親ゾーンから受け取っていることを確認できます。
$ dig example.com +trace +multi dnskey ; <<>> DiG 9.10.6 <<>> example.com +trace +multi dnskey ;; global options: +cmd . 22092 IN NS m.root-servers.net. . 22092 IN NS l.root-servers.net. . 22092 IN NS g.root-servers.net. . 22092 IN NS b.root-servers.net. . 22092 IN NS h.root-servers.net. . 22092 IN NS c.root-servers.net. . 22092 IN NS e.root-servers.net. . 22092 IN NS d.root-servers.net. . 22092 IN NS a.root-servers.net. . 22092 IN NS k.root-servers.net. . 22092 IN NS f.root-servers.net. . 22092 IN NS i.root-servers.net. . 22092 IN NS j.root-servers.net. . 22092 IN RRSIG NS 8 0 518400 ( 20240329170000 20240316160000 30903 . Kz1XXMM1HdcnYR8VRHl0oprAVoKDRqizsPJ5aAFUVvbW IwXtA34Sy4DPnRAuJDKlobqEaHd4kBfiq7tUWeTaxzhT UIIgHW5sL1ZxhzL3M6wZdjXq8cCUasnOtFT/pf2vBRel +OJmjS0q5CcksOMDhTQd52PJD5Wtrth2ct/deXt7eFLa rrHMVj/yTRGXstMQHMv1C2UJh/RLRFQfAMpbUbn11JQf FlCRegxz/z+orxyoyZD+Jsztpq3oa9XdC6Gkzd7TOiBZ zWJX4T9uZKzLmXU6qvv0vaXBQdlc8acSAmRLTUmDf3pV q8+BdjzXqHgCyxtYqEdx/PkagemLR6gKUw== ) ;; Received 525 bytes from 192.168.24.254#53(192.168.24.254) in 26 ms com. 172800 IN NS m.gtld-servers.net. com. 172800 IN NS d.gtld-servers.net. com. 172800 IN NS i.gtld-servers.net. com. 172800 IN NS f.gtld-servers.net. com. 172800 IN NS j.gtld-servers.net. com. 172800 IN NS l.gtld-servers.net. com. 172800 IN NS c.gtld-servers.net. com. 172800 IN NS e.gtld-servers.net. com. 172800 IN NS k.gtld-servers.net. com. 172800 IN NS b.gtld-servers.net. com. 172800 IN NS a.gtld-servers.net. com. 172800 IN NS h.gtld-servers.net. com. 172800 IN NS g.gtld-servers.net. com. 86400 IN DS 19718 13 2 ( 8ACBB0FD28F41250A80A491389424D341522D946B0DA 0C0291F2D3D771D7805A ) com. 86400 IN RRSIG DS 8 1 86400 ( 20240330050000 20240317040000 30903 . XnVAtwXaG95u0NJIMbibWJI3XpVI7z/AQ3tu55/cHHXR pzmdHdUv9N5hDwRVGPAGCobOvRTMYjGuA5pBw2jWXwSQ ij/bnll22SiQF2cOVGF+XvJQ0OeSfOpl9Glc0myG/ONG DuxZMIrArWum0Vs/xSZ0DNIs062PAquv+ig1jNnmKltl KMJstEcPdoxoKHozHzH8/XRy5MnIlxHmuONfMv6m3Wqe MJZrDI2F8qkKH6U8RDWXvLTgwMD8T/oY37ubXT3jR75A tz2CwAXxbXiK8nChIb2B2cpPRxQ4iI9ZsvVE7FnzojUi H7lPDJRrNb2L59G6Ifev302s2gt7/de84A== ) ;; Received 1180 bytes from 192.112.36.4#53(g.root-servers.net) in 35 ms example.com. 172800 IN NS ns-160.awsdns-20.com. example.com. 172800 IN NS ns-801.awsdns-36.net. example.com. 172800 IN NS ns-1911.awsdns-46.co.uk. example.com. 172800 IN NS ns-1503.awsdns-59.org. CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN NSEC3 1 1 0 - ( CK0Q2D6NI437EQH8NA30NS61O48UL8G5 NS SOA RRSIG DNSKEY NSEC3PARAM ) CK0POJMG874LJREF7EFN8430QVIT8BSM.com. 86400 IN RRSIG NSEC3 13 2 86400 ( 20240321042502 20240314031502 4534 com. l+wDDgtHvPd6zIcxrg5bC3s1DrwR56OUep9fDtjmezTb 7gmboYOYGKaC44fC+Nf+t5s47u21idzwJVCQtmx8sg== ) 7B6529LACI82MRS1IUTK35JAL7BIB15M.com. 86400 IN NSEC3 1 1 0 - ( 7B65EVDGGKFBAVN3N2PUNLS54ORVC1IV NS DS RRSIG ) 7B6529LACI82MRS1IUTK35JAL7BIB15M.com. 86400 IN RRSIG NSEC3 13 2 86400 ( 20240324054622 20240317043622 4534 com. 3l/ubbjGIV+hYm9SH3We/SzgjoymWKOomwMzHmVow+tm AyudE2GKgeWd5leANwutH8Djnjh8K+zszcF7uJLoxQ== ) ;; Received 556 bytes from 192.52.178.30#53(k.gtld-servers.net) in 127 ms example.com. 900 IN SOA ns-801.awsdns-36.net. awsdns-hostmaster.amazon.com. ( 1 ; serial 7200 ; refresh (2 hours) 900 ; retry (15 minutes) 1209600 ; expire (2 weeks) 86400 ; minimum (1 day) ) ;; Received 127 bytes from 205.251.195.33#53(ns-801.awsdns-36.net) in 89 ms
上記のdigコマンドでは対象のドメインからDNSKEYレコードを取得するように指定して実行しましたが、対象ドメインではDNSSECが有効になっていないためSOAレコードが返却されています。 また、DSレコードをcomゾーンの権威サーバに登録していないため、不在証明のNSEC3レコードも返却されています。
トレースせずにDNSSECが有効化されていないことも確認できます。以下はGoogle Public DNSに対して対象ドメインのサブドメインとして登録されているWebサイトを名前解決してみた結果です。
$ dig @8.8.8.8 www.example.com ; <<>> DiG 9.10.6 <<>> @8.8.8.8 www.example.com ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 59806 ;; flags: qr rd ra; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1 (以下省略)
実際取得できたAレコードの部分は省略しましたが、上記結果で着目するのはヘッダー内の「flags: qr rd ra」の部分です。digコマンドではヘッダーに含まれるビット情報を「flags」という項目で表示しています。DNSSECが有効な場合、この「flags」に「ad」というビットが含まれるようになります。今回はもちろん「ad」ビットは含まれていません。
また、whoisコマンドでもDNSSECの状態を確認できました。
$ whois example.com | grep -i dnssec DNSSEC: unsigned DNSSEC: unsigned DNSSEC: unsigned
なお、whoisについては全てのドメインでDNSSECの状態を確認できるわけではありません。
やってみた
Route 53でDNSSECを有効化するには、まず対象のホストゾーンで[DNSSEC 署名を有効化する]を選択してキー署名キー(KSK)を作成します。
キー署名キー(KSK)はAWS KMSのカスタマー管理のCMKとして作成できます。既存のCMKが存在しない場合は[カスタマー管理のCMKの作成]を選択します。
KSKが作成されると、対象のホストゾーンでアクティブなKSKとして表示されます。
作成されたKSKを選択して[詳細を表示]すると、信頼チェーンを確立するための情報が表示されます。今回はレジストラとしてRoute 53を使用しているドメインを対象としているため、[Route 53 レジストラ]の各種項目をメモします。
[登録済みドメイン]から対象のドメインを選択し、DNSSECキーを追加します。
先ほどメモした内容を入力します。[キータイプ]および[アルゴリズム]についてはデフォルトで選択されている内容とメモした情報が一致しているはずです。
[追加]を選択すると元の画面に戻り、以下のようなメッセージが表示されました。
今回の検証ではメールはすぐに届きました。文面をそのまま公開することは避けますが、内容としては対象のドメインでDNSSEC有効化のリクエストを受けとったこと、およびリクエストが意図したものである場合は特に何もする必要はないですよという旨が記載されていました。
[登録済みドメイン]の[DNSSECキー]画面を更新すると、以下のようにDNSSECのステータスは有効となり、DNSSECキーが登録されていることを確認できます。
以上でDNSSECの有効化は完了となります。
ZSKの設定は?となるかもしれませんが、こちらに以下のとおり記載されています。
ZSK 管理は Route 53 によって実行されます。
DNSSEC有効化後
改めて「DNSViz」を使って可視化してみます。
対象ゾーンにもDNSKEYレコードが追加され、ルートゾーンとcomゾーン間と同じようにcomゾーンと対象ゾーンの間でも信頼関係が結ばれていることが確認できました。 なお、警告マークがDNSSEC有効化前から残っていますが今回の検証とは無関係です。(内容としてはRoute 53で使われている権威サーバのIPv6に関するグルーレコードが登録されていないと表示されていました)
DNSSEC有効化前と同じくトレースオプション付きでdigコマンドを実行してみます。
$ dig example.com +trace +multi dnskey ; <<>> DiG 9.10.6 <<>> example.com +trace +multi dnskey ;; global options: +cmd . 120394 IN NS i.root-servers.net. . 120394 IN NS d.root-servers.net. . 120394 IN NS h.root-servers.net. . 120394 IN NS a.root-servers.net. . 120394 IN NS l.root-servers.net. . 120394 IN NS g.root-servers.net. . 120394 IN NS j.root-servers.net. . 120394 IN NS f.root-servers.net. . 120394 IN NS b.root-servers.net. . 120394 IN NS e.root-servers.net. . 120394 IN NS m.root-servers.net. . 120394 IN NS k.root-servers.net. . 120394 IN NS c.root-servers.net. ;; Received 811 bytes from 2001:a7ff:5f01::a#53(2001:a7ff:5f01::a) in 25 ms com. 172800 IN NS a.gtld-servers.net. com. 172800 IN NS b.gtld-servers.net. com. 172800 IN NS c.gtld-servers.net. com. 172800 IN NS d.gtld-servers.net. com. 172800 IN NS e.gtld-servers.net. com. 172800 IN NS f.gtld-servers.net. com. 172800 IN NS g.gtld-servers.net. com. 172800 IN NS h.gtld-servers.net. com. 172800 IN NS i.gtld-servers.net. com. 172800 IN NS j.gtld-servers.net. com. 172800 IN NS k.gtld-servers.net. com. 172800 IN NS l.gtld-servers.net. com. 172800 IN NS m.gtld-servers.net. com. 86400 IN DS 19718 13 2 ( 8ACBB0CD28341250A80A491389424D341522D946B0DA 0C0291F2D3D771D7805A ) com. 86400 IN RRSIG DS 8 1 86400 ( 20240330050000 20240317040000 30903 . XnVAtwXaG95u0NJIMbibWJI3XpVI7z/AQ3tu55/cHHXR pzmdHdUv9N5hDwRVGPAGCobOvRTMYjGuA5pBw2jWXwSQ ij/bnll22S3QF2cOVGF+XvJQ0OeSfOpl9Glc0myG/ONG DuxZMIrArWum0Vs/xSZ0DNIs062PAquv+ig1jNnmKltl KMJstEcPLoxoKHozHzH8/XRy5MnIlxHmuONfMv6m3Wqe MJZrDI2F8qkKH6U8RDWXvLTgwMD8T/oY37ubXT3jR75A tz2CwAXxbXiK8nChIb2B2cpPRxQ4iI9ZsvVE7FnzojUi H7lPDJRrNb2L59G6Ifev302s2gt7/de84A== ) ;; Received 1171 bytes from 198.97.190.53#53(h.root-servers.net) in 29 ms example.com. 172800 IN NS ns-160.awsdns-20.com. example.com. 172800 IN NS ns-801.awsdns-36.net. example.com. 172800 IN NS ns-1911.awsdns-46.co.uk. example.com. 172800 IN NS ns-1503.awsdns-59.org. example.com. 86400 IN DS 18409 13 2 ( AD3B4FCC3EAD69BF8DDAD82A86B6606562FC1F6A91DC 55F7F23A8C9D8FB3E63C ) example.com. 86400 IN RRSIG DS 13 2 86400 ( 20240324153324 20240317142324 4534 com. L6atrlXhrFwQ3hBF1th5Wo1bXiB1Es9OXkPqiLKP3NQ2 LQLjqEjXlcJ4gkfSBdSrH/R/ymFvjqBMsc7Xykwb9w== ) ;; Received 340 bytes from 192.35.51.30#53(f.gtld-servers.net) in 136 ms example.com. 3600 IN DNSKEY 256 3 13 ( AYEjwxixu++XqEzT82P9e2Oa/FLA+/POsfLZ+dHzJrTQ 21wX/AtSctAOwf3A6rDZtX6pK7mA+BbmfzzMgUqDtA== ) ; ZSK; alg = ECDSAP256SHA256 ; key id = 11114 example.com. 3600 IN DNSKEY 257 3 13 ( VlZhcp7CY385gnJeJJf7LO/7E9aHlpEIlZaQD4ht+XvO EsUHVFbEFmkKXzE0cBieMfZ9JSdKZVRkvNMkOs2JsA== ) ; KSK; alg = ECDSAP256SHA256 ; key id = 18409 example.com. 3600 IN RRSIG DNSKEY 13 2 3600 ( 20240317180000 20240317070000 18409 example.com. zI3AIObFmdDo+KqK1+C9+QbulhFKWThxClMSl3kuGGk/ +zrOfnkI6H009RWgauTMELi5Ah85Gbm4B9Ti0yTWUg== ) ;; Received 307 bytes from 2600:9000:5303:2100::1#53(ns-801.awsdns-36.net) in 81 ms
対象ゾーンからDNSKEYレコードが取得できていることを確認できます。また、comゾーンの権威サーバが今回は不在証明のNSEC3レコードではなくDSレコードを返してくれています。
同様にGoogle Public DNSに対して対象ドメインのサブドメインとして登録されているWebサイトの名前解決を再度digコマンドで実行してみます。
$ dig @8.8.8.8 www.example.com ; <<>> DiG 9.10.6 <<>> @8.8.8.8 www.example.com ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 13987 ;; flags: qr rd ra ad; QUERY: 1, ANSWER: 4, AUTHORITY: 0, ADDITIONAL: 1 (以下省略)
「flags」に「ad」ビットが追加されました。
また、whoisコマンドを打ってみると以下のように変わりました。
$ whois example.com | grep -i dnssec DNSSEC: signedDelegation DNSSEC DS Data: 18409 13 2 AD3B4FCC3EAC69BF8DDAF82A86B6606562FC1F6A91DC55F7F23A8C9D8FB3E63C DNSSEC: signedDelegation DNSSEC: signedDelegation
まとめ
Route 53でDNSSECを有効化する方法と、実際に有効化する前後で確認する内容についてご紹介しました。
ただし、本来はDNSSECを有効化する前にゾーンの可用性を監視したり最大TTLを下げたりすることが前提としてAWSのドキュメントにも記載されていますので、本番環境に適用する際はご注意ください。
また、実際に色々なドメインに対して今回のようにdigコマンドを実行してみたりDNSVizで可視化してみたりすると分かりますが、DNSSECを有効化していないサイトも数多く存在します。
セキュリティのことを考えてメリットだけを見るととりあえず有効化すべきなのではと思ってしまいますが、こちらのような事例もあったりするらしいので何か起きた時にはトラブルシューティングできる必要があります。さらにあるべきではKSKのローテーションも行う必要があるため、そういった運用も発生するということを踏まえてDNSSECの有効化は慎重に適用した方が良いと思いました。
まとめ2(追記)
本記事を投稿後、DNSSEC有効化に関連したトラブル事例を弊社内の先達から紹介いただきました。
その事例の中でも特にSlack社のこちらの「Unsuccessful attempt two」と「Unsuccessful attempt three」は必見でした。思わず上記まとめの締めを取り消した勢いです。
訂正します。「DNSSECの有効化は『必ず』慎重に適用『しなければなりません』」。
Slack社の事例のように、DNSSECを有効化する際に想定外のトラブルに遭遇した場合、最悪のケースでは長時間に渡って対象ドメインの名前解決ができなくなります。対象ドメインの名前解決ができないということは、そのドメインで提供しているサービスが全く使えなくなるということです。
併せて追記したこちらの事例も要注意です。こちらはドメイン移管前の注意点としてよく見かけるためSlack社の事例よりは一般的ですが、ざっくり言うとDNSSECを有効化したままのドメインを別レジストラに移管した場合、対象ドメインの名前解決ができなくなります。対象ドメインの名前解決ができないということは、そのドメインで提供しているサービスが全く使えなくなるということです。
上記リスクとキャッシュポイズニングなどのセキュリティリスクを天秤にかけながら導入の要否を慎重に検討する必要があります。